package com.life.ai.server.framework.syslog.aspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import com.life.ai.server.common.utils.ServletUtils;
import com.life.ai.server.common.utils.SpringUtils;
import com.life.ai.server.framework.syslog.annotation.SysLog;
import com.life.ai.server.framework.syslog.event.SysLogEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @author soupcat
 * @version 1.0
 * @date 2021/11/9 14:24
 */
@Slf4j
@Aspect
@Component
public class SysLogAspect {

    @Around("@annotation(sysLog)")
    @SneakyThrows
    public Object around(ProceedingJoinPoint point, SysLog sysLog) {
        Object proceed;
        long startTime = System.currentTimeMillis();

        SysLogEvent sysLogEvent = createSysLogEvent(sysLog);
        String className = point.getSignature().getDeclaringTypeName();
        String methodName = point.getSignature().getName();
        sysLogEvent.setClassName(className);
        sysLogEvent.setMethodName(methodName);
        if (sysLog.saveReq()) {
            // 请求参数
            sysLogEvent.setParams(StrUtil.sub(JSONUtil.toJsonStr(point.getArgs()), 0, 6000));
        }
        try {
            proceed = point.proceed();
            // 返回参数
            if (sysLog.saveResp()) {
                setResultValue(sysLogEvent, proceed);
            }
        } catch (Throwable e) {
            // 记录栈异常信息
            sysLogEvent.setHasError(true)
                    .setException(ExceptionUtil.stacktraceToString(e));
            throw (e);
        } finally {
            // 执行时间
            sysLogEvent.setExecuteTime(System.currentTimeMillis() - startTime);
            SpringUtils.context().publishEvent(sysLogEvent);
        }
        return proceed;
    }

    private SysLogEvent createSysLogEvent(SysLog sysLog) {
        HttpServletRequest request = ServletUtils.getRequest();
        SysLogEvent sysLogEvent = new SysLogEvent()
                .setTitle(sysLog.value())
                .setRemoteAddr(ServletUtils.getClientIP())
                .setUserAgent(request.getHeader("User-Agent"))
                .setRequestUri(URLUtil.getPath(request.getRequestURI()))
                .setRequestMethod(request.getMethod())
                .setOperateTime(new Date())
                .setExecuteTime(0L)
                .setHasError(false);
        if (StpUtil.isLogin()) {
            sysLogEvent.setCreateBy(StpUtil.getLoginIdAsLong());
        }
        return sysLogEvent;
    }

    private void setResultValue(SysLogEvent sysLogEvent, Object proceed) {
        String str = "";
        try {
            str = JSONUtil.toJsonStr(proceed);
        } catch (Exception ignored) {
        }
        sysLogEvent.setResults(str);
    }
}
